#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>

#include <netinet/ip.h>
#include <netinet/tcp.h>

// 缓冲区足够大，最大以太网帧长度
#define BUFSIZE 2048

// 打印以太网头
void print_ethhdr(struct ether_header *eth) {
    printf("Ethernet: src=%s dst=%s type=0x%04x\n",
        ether_ntoa((struct ether_addr *)eth->ether_shost),
        ether_ntoa((struct ether_addr *)eth->ether_dhost),
        ntohs(eth->ether_type));
}

// 打印IP头
void print_iphdr(struct iphdr *ip) {
    struct in_addr s, d;
    s.s_addr = ip->saddr;
    d.s_addr = ip->daddr;
    printf("IP: src=%s dst=%s proto=%d\n",
        inet_ntoa(s), inet_ntoa(d), ip->protocol);
}

// 打印TCP头
void print_tcphdr(struct tcphdr *tcp) {
    printf("TCP: sport=%u dport=%u flags=",
        ntohs(tcp->source), ntohs(tcp->dest));
    if (tcp->syn) printf("SYN ");
    if (tcp->ack) printf("ACK ");
    if (tcp->fin) printf("FIN ");
    if (tcp->rst) printf("RST ");
    if (tcp->psh) printf("PSH ");
    if (tcp->urg) printf("URG ");
    printf("\n");
}

int main() {
    // 1. 创建raw socket用于抓包
    int raw_sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (raw_sock < 0) {
        perror("socket(AF_PACKET) failed");
        return 1;
    }

    // 2. 绑定到指定网卡
    struct sockaddr_ll sll;
    memset(&sll, 0, sizeof(sll));
    sll.sll_family = AF_PACKET;
    sll.sll_protocol = htons(ETH_P_ALL);

    // 修改为你自己的网卡名
    const char *ifname = "ens33";
    sll.sll_ifindex = if_nametoindex(ifname);
    if (sll.sll_ifindex == 0) {
        perror("if_nametoindex failed");
        close(raw_sock);
        return 1;
    }
    if (bind(raw_sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
        perror("bind raw_sock failed");
        close(raw_sock);
        return 1;
    }

    // 3. 创建UDP socket
    int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_sock < 0) {
        perror("socket(AF_INET) failed");
        close(raw_sock);
        return 1;
    }

    struct sockaddr_in udp_addr;
    memset(&udp_addr, 0, sizeof(udp_addr));
    udp_addr.sin_family = AF_INET;
    udp_addr.sin_port = htons(9000); // 目标端口
    if (inet_pton(AF_INET, "192.168.1.100", &udp_addr.sin_addr) != 1) {
        perror("inet_pton failed");
        close(raw_sock);
        close(udp_sock);
        return 1;
    }

    printf("Start capturing packets on interface %s...\n", ifname);

    // 4. 主循环：抓包->解析->通过UDP转发
    while (1) {
        unsigned char buf[BUFSIZE];
        ssize_t n = recvfrom(raw_sock, buf, BUFSIZE, 0, NULL, NULL);
        if (n < 0) {
            if (errno == EINTR)
                continue;
            perror("recvfrom failed");
            break;
        }

        if (n < sizeof(struct ether_header))
            continue;

        struct ether_header *eth = (struct ether_header *)buf;
        print_ethhdr(eth);

        // 只解析IPv4包
        if (ntohs(eth->ether_type) == ETH_P_IP) {
            if (n < sizeof(struct ether_header) + sizeof(struct iphdr))
                continue;
            struct iphdr *ip = (struct iphdr *)(buf + sizeof(struct ether_header));
            print_iphdr(ip);

            // 只解析TCP包
            if (ip->protocol == IPPROTO_TCP) {
                int iphdr_len = ip->ihl * 4;
                if (n < sizeof(struct ether_header) + iphdr_len + sizeof(struct tcphdr))
                    continue;
                struct tcphdr *tcp = (struct tcphdr *)(buf + sizeof(struct ether_header) + iphdr_len);
                print_tcphdr(tcp);
            }
        }

        // 转发原始包
        ssize_t sent = sendto(udp_sock, buf, n, 0,
                              (struct sockaddr *)&udp_addr, sizeof(udp_addr));
        if (sent != n) {
            perror("sendto (UDP) failed");
        }
    }

    close(raw_sock);
    close(udp_sock);
    return 0;
}
